package com.ldy.core.util;

import java.io.IOException;
import java.net.InetAddress;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpException;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.HttpResponseInterceptor;
import org.apache.http.NameValuePair;
import org.apache.http.NoHttpResponseException;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.config.RequestConfig.Builder;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import com.alibaba.fastjson.JSONObject;

public class RequestClient {
	
	private static final int timeout = 10000;
	
	private static final Logger logger = LoggerFactory.getLogger(RequestClient.class);
	


	/**
	 * 返回封装
	 */
	public static class Response {
		int status;
		String data;
		Header[] headers;
		Header[] preHeaders;
		
		long times;

		public Response() {
		}

		public Response(int status, String data, Header[] headers,long times) {
			this.status = status;
			this.data = data;
			this.headers = headers;
			this.times = times;
		}

		public int getStatus() {
			return status;
		}

		public void setStatus(int status) {
			this.status = status;
		}

		public String getData() {
			return data;
		}

		public void setData(String data) {
			this.data = data;
		}

		public Header[] getHeaders() {
			return headers;
		}

		public void setHeaders(Header[] headers) {
			this.headers = headers;
		}

		public Header[] getPreHeaders() {
			return preHeaders;
		}

		public void setPreHeaders(Header[] preHeaders) {
			this.preHeaders = preHeaders;
		}

		public long getTimes() {
			return times;
		}

		public void setTimes(long times) {
			this.times = times;
		}
		
	}

	public static String getRequest(String url) {
		// 创建HttpClient并设置代理
		CloseableHttpClient httpClient = HttpClients.custom().build();
		// 创建HttpComponentsClientHttpRequestFactory实例
		HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
		// 将自定义的HttpClient设置到工厂中
		requestFactory.setHttpClient(httpClient);
		// 使用工厂创建RestTemplate实例
		RestTemplate restTemplate = new RestTemplate(requestFactory);
		ResponseEntity<String> entity = restTemplate.getForEntity(url, String.class);
		return entity.getBody();
	}
	 
	 public static String postJSON(RestTemplate temp, String url, JSONObject params) {
		 	HttpHeaders headers = new HttpHeaders();
			headers.setContentType(MediaType.APPLICATION_JSON);
			org.springframework.http.HttpEntity<JSONObject> entity = new org.springframework.http.HttpEntity<>(params,
					headers);
			ResponseEntity<String> res = temp.postForEntity(url, entity, String.class);
			return res.getBody();
	 }

	public static String postJSON(String url, JSONObject params) {
		// 创建HttpClient并设置代理
		CloseableHttpClient httpClient = HttpClients.custom().build();
		// 创建HttpComponentsClientHttpRequestFactory实例
		HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
		// 将自定义的HttpClient设置到工厂中
		requestFactory.setHttpClient(httpClient);
		requestFactory.setConnectTimeout(50000);
		requestFactory.setReadTimeout(50000);
		requestFactory.setConnectionRequestTimeout(50000);
		// 使用工厂创建RestTemplate实例
		RestTemplate restTemplate = new RestTemplate(requestFactory);
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_JSON);
		org.springframework.http.HttpEntity<JSONObject> entity = new org.springframework.http.HttpEntity<>(params,
				headers);
		ResponseEntity<String> res = restTemplate.postForEntity(url, entity, String.class);
		return res.getBody();
	}

	public static Response get(String url, HttpHost proxy) throws IOException {
		HttpClientBuilder builder = HttpClients.custom().setDefaultCookieStore(new BasicCookieStore());
		if (proxy != null) {
			builder.setProxy(proxy);
		}
		CloseableHttpClient httpClient = builder.build();
		try {
			HttpGet httpGet = new HttpGet(url);
			CloseableHttpResponse response = httpClient.execute(httpGet);
			HttpEntity responseEntity = response.getEntity();
			String responseBody = null;
			if (responseEntity != null) {				
				responseBody = EntityUtils.toString(responseEntity, "UTF-8");
			}
			return new Response(response.getStatusLine().getStatusCode(), responseBody, response.getAllHeaders(), 0);
		} finally {
			httpClient.close();
		}
	}
	
	public static void main(String[] args) {
		
		try {
			String url = "https://static.tianqistatic.com/static/wap2018/ico1/b1.png";
			Map<String, String> header = new HashMap<String, String>();
			header.put("referer", "https://www.tianqi.com/");
			header.put("User-Agent", "PostmanRuntime/7.42.0");
			 Response response = RequestClient.get(url, header, null);
			 System.out.println(response.getData());
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * get 请求
	 * 
	 * @param url
	 * @param headers
	 * @param proxy
	 * @return
	 * @throws IOException
	 */
	public static Response get(String url, Map<String, String> headers, HttpHost proxy) throws IOException {
		return get(url, headers, null, proxy);
	}
	
	/**
	 * get 请求
	 * 
	 * @param url
	 * @param headers
	 * @param proxy
	 * @return
	 * @throws IOException
	 */
	public static Response get(String url, Map<String, String> headers, Map<String, String> params, HttpHost proxy)
			throws IOException {
		return get(url, headers, params, proxy, null, null);
	}
	
	public static Response get(String url, Map<String, String> headers, Map<String, String> params, HttpHost proxy, String username, String pwd)
			throws IOException {
		return get(url, headers, params, proxy, username, pwd, 2);
	}

	/**
	 * get 请求
	 * 
	 * @param url
	 * @param headers
	 * @param proxy
	 * @return
	 * @throws IOException
	 */
	public static Response get(String url, Map<String, String> headers, Map<String, String> params, HttpHost proxy, String username, String pwd, int size)
			throws IOException {
		HttpClientBuilder builder = HttpClients.custom().setDefaultCookieStore(new BasicCookieStore());
		try {
			URIBuilder uriBuilder = new URIBuilder(url);
			if (params != null) {
				for (String key : params.keySet()) {
					uriBuilder.addParameter(key, params.get(key));
				}
			}
			HttpGet httpGet = new HttpGet(uriBuilder.build());
			if (headers != null) {
				for (String key : headers.keySet()) {
					httpGet.setHeader(key, headers.get(key));
				}
			}

			CloseableHttpResponse response = null;
			Builder builder2 = RequestConfig.custom().setSocketTimeout(timeout) // 读取数据超时时间
					.setConnectTimeout(timeout) // 连接超时时间
					.setConnectionRequestTimeout(timeout);
			httpGet.setConfig(builder2.build());
			if (proxy != null && "socks".equals(proxy.getSchemeName())) {
				response = setSocksProxy(httpGet, builder, proxy.getHostName(), proxy.getPort(), username, pwd);
			} else if (proxy != null) {
				response = setHttpProxy(httpGet, builder, proxy.getHostName(), proxy.getPort(),  username, pwd);
			} else {
				response = builder.build().execute(httpGet);
			}
			HttpEntity responseEntity = response.getEntity();
			String responseBody = null;
			if (responseEntity != null) {				
				responseBody = EntityUtils.toString(responseEntity, "UTF-8");
			}
			Response res = new Response(response.getStatusLine().getStatusCode(), responseBody, response.getAllHeaders(), 0);
			// 去发请求的
			res.setPreHeaders(httpGet.getAllHeaders());
			return res;
		} catch (NoHttpResponseException e) {
			if (--size > 0) {				
				return get(url, headers, params, proxy, username, pwd, size);
			}
			throw e;
		} catch (Exception e) {
			throw new IOException(e);
		} finally {
//			httpClient.close();
		}
	}
	

	public static Response post(String url, Map<String, String> headers, HttpEntity params, HttpHost proxy)
			throws IOException {
		return post(url, headers, params, proxy, 2);
	}
	/**
	 * post 请求
	 * 
	 * @param url
	 * @param headers
	 * @param params
	 * @param proxy
	 * @param size
	 * @return
	 * @throws IOException
	 */
	public static Response post(String url, Map<String, String> headers, HttpEntity params, HttpHost proxy, int size)
			throws IOException {
		HttpClientBuilder builder = HttpClients.custom().setDefaultCookieStore(new BasicCookieStore());
		try {
			HttpPost httpPost = new HttpPost(url);
			if (headers != null) {
				for (String key : headers.keySet()) {
					httpPost.setHeader(key, headers.get(key));
				}
			}
			if (params != null) {
				// HttpEntity entity = new UrlEncodedFormEntity(nvps, StandardCharsets.UTF_8);
				// HttpEntity entity = new StringEntity(params.toJSONString(), "UTF-8");
				httpPost.setEntity(params);
			}
			CloseableHttpResponse response = null;
			Builder builder2 = RequestConfig.custom().setSocketTimeout(timeout) // 读取数据超时时间
					.setConnectTimeout(timeout) // 连接超时时间
					.setConnectionRequestTimeout(timeout);
			httpPost.setConfig(builder2.build());
			if (proxy != null && "socks".equals(proxy.getSchemeName())) {
				response = setSocksProxy(httpPost, builder, proxy.getHostName(), proxy.getPort(), null, null);
			} else if (proxy != null){
				response = setHttpProxy(httpPost, builder, proxy.getHostName(), proxy.getPort(),  null, null);
			} else {
				response = builder.build().execute(httpPost);
			}
			HttpEntity responseEntity = response.getEntity();
			String responseBody = null;
			if (responseEntity != null) {				
				responseBody = EntityUtils.toString(responseEntity, "UTF-8");
			}
			return new Response(response.getStatusLine().getStatusCode(), responseBody, response.getAllHeaders(), 0);
		} catch (NoHttpResponseException e) {
			if (--size > 0) {				
				return post(url, headers, params, proxy, size);
			}
			throw e;
		}catch(Exception e) {
			logger.error("", e);
			throw new IOException(e);
		}finally {
//			httpClient.close();
		}
	}
	
	
	/**
	 * http 代理
	 * 
	 * @param httpPost
	 * @param build
	 * @param proxyIp
	 * @param port
	 * @param username
	 * @param pwd
	 * @return
	 * @throws Exception
	 */
	private static CloseableHttpResponse setHttpProxy(HttpRequestBase httpPost, HttpClientBuilder build, String proxyIp,
			int port, String username, String pwd) throws Exception {
		if (!StringUtils.isEmpty(proxyIp)) {
//			logger.info("使用http代理: proxyIp:{}, port:{}, username: {}, pwd: {}", proxyIp, port, username, pwd);
			// 使用代理
			CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
			if (!StringUtils.isEmpty(username)) {
				credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, pwd));
			}
			HttpHost proxy = new HttpHost(proxyIp, port, "http");
			build.setProxy(proxy).setDefaultCredentialsProvider(credentialsProvider);
		}
		CloseableHttpClient httpclient = build.build();

		return httpclient.execute(httpPost);
	}
	
	/**
	 * socks 代理
	 * 
	 * @param httpPost
	 * @param build
	 * @param proxyHost
	 * @param proxyPort
	 * @param proxyName
	 * @param proxyPwd
	 * @return
	 * @throws Exception
	 */
	private static CloseableHttpResponse setSocksProxy(HttpRequestBase httpPost, HttpClientBuilder build, String proxyHost,
			int proxyPort, String proxyName, String proxyPwd) throws Exception {
		logger.info("使用socks代理: proxyIp:{}, port:{}, username: {}, pwd: {}", proxyHost, proxyPort, proxyName, proxyPwd);
		// 用户名和密码验证
//		Authenticator.setDefault(new Authenticator() {
//			protected PasswordAuthentication getPasswordAuthentication() {
//				PasswordAuthentication p = new PasswordAuthentication(proxyName, proxyPwd.toCharArray());
//				return p;
//			}
//		});
//		HttpClientContext context = HttpClientContext.create();
//		 SSLContext sslContext = SSLContextBuilder.create()
//                 .loadTrustMaterial(new TrustStrategy() {
//                     @Override
//                     public boolean isTrusted(X509Certificate[] chain, String authType) {
//                         return true;  // 信任所有证书
//                     }
//                 })
//                 .build();
//		Registry<ConnectionSocketFactory> reg = RegistryBuilder.<ConnectionSocketFactory>create()
//				.register("http", new MyConnectionSocketFactory())
//				.register("https", new MySSLConnectionSocketFactory(sslContext)).build();
//		
//		PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(reg);
//		CloseableHttpClient httpclient = build.setConnectionManager(cm).build();
//		InetSocketAddress socksaddr = new InetSocketAddress(localAddress, 0);
//		context.setAttribute("socks.address", socksaddr);
		
		InetAddress localAddress = InetAddress.getByName(proxyHost);
		httpPost.setConfig(RequestConfig.custom().setLocalAddress(localAddress).build());
		return build.build().execute(httpPost);
	}
	

	public static HttpEntity getJsonParams(JSONObject json) {
		return new StringEntity(json.toJSONString(), "UTF-8");
	}

	public static HttpEntity getParams(JSONObject json) {
		List<NameValuePair> nvps = new ArrayList<>();
		for (String key : json.keySet()) {
			nvps.add(new BasicNameValuePair(key, json.getString(key)));
		}
		return new UrlEncodedFormEntity(nvps, StandardCharsets.UTF_8);
	}
	
	/**
	 * 获取 cookies
	 * 
	 * @param allHeaders
	 * @return
	 */
	public static List<String> getCookies(Header[] allHeaders) {
		return Arrays.asList(allHeaders).stream().filter(c -> "set-cookie".equals(c.getName().toLowerCase())).map(c -> c.getValue())
				.collect(Collectors.toList());
	}

	/**
	 * 获取 header
	 * 
	 * @param allHeaders
	 * @return
	 */
	public static Map<String, String> getHeaders(Header[] allHeaders) {
		Map<String, String> map = new HashMap<String, String>();
		for (Header h : allHeaders) {
			map.put(h.getName(), h.getValue());
		}
		return map;
	}

	/**
	 * 获取 cookies
	 * 
	 * @param cookies
	 * @return
	 */
	public static Map<String, String> getCookies(List<String> cookies) {
		Map<String, String> map = new HashMap<String, String>();
		for (String h : cookies) {
			String[] split = h.split(";");
			if (split.length>0) {
				int indexOf = split[0].indexOf("=");
				String[] split2 = split[0].split("=");
				if (indexOf != -1 && split2.length > 1) {					
					map.put(split2[0], split[0].substring(indexOf+1));
				}
			}
		}
		return map;
	}

	public static String cookieStr(List<String> cookies) {
		// 实现将cookies转换为字符串的逻辑
		return cookies.stream().collect(Collectors.joining("; "));
	}

	/**
	 * 打开页面
	 * 
	 * @param url
	 * @return
	 * @throws IOException
	 */
	public static Response gotoPage(String url, Map<String, String> headers, HttpHost proxy) throws IOException {
		Response result = new Response();
		HttpResponseInterceptor interceptor = new HttpResponseInterceptor() {
			@Override
			public void process(HttpResponse response, HttpContext context) throws HttpException, IOException {
				if (response.getStatusLine().getStatusCode() >= 300 && response.getStatusLine().getStatusCode() < 400) {
					Header locationHeader = response.getFirstHeader("Location");
					Header[] allHeaders = response.getAllHeaders();
					if (locationHeader != null) {
						result.setPreHeaders(allHeaders);
					}
				}
			}
		};
		// 配置HttpClient以使用自定义的HttpResponseInterceptor
		HttpClientBuilder builder = HttpClients.custom().setDefaultCookieStore(new BasicCookieStore()).addInterceptorLast(interceptor);
//		if (proxy != null) {
//			builder.setProxy(proxy);
//		}
//		CloseableHttpClient httpClient = builder.build();
		try {
			HttpGet httpGet = new HttpGet(url);
			if (headers != null) {
				for (String key : headers.keySet()) {
					httpGet.setHeader(key, headers.get(key));
				}
			}
			try {
				CloseableHttpResponse response = null;
				if (proxy != null && "socks".equals(proxy.getSchemeName())) {
					response = setSocksProxy(httpGet, builder, proxy.getHostName(), proxy.getPort(), null, null);
				} else if (proxy != null){
					response = setHttpProxy(httpGet, builder, proxy.getHostName(), proxy.getPort(),  null, null);
				} else {
					response = builder.build().execute(httpGet);
				}
			
				result.setHeaders(response.getAllHeaders());
				result.setStatus(response.getStatusLine().getStatusCode());
				// 获取响应实体
				HttpEntity entity = response.getEntity();
				if (entity != null) {
					String responseString = EntityUtils.toString(entity, "UTF-8");
					result.setData(responseString);
				}
				return result;
			}catch(Exception e) {
				throw new IOException(e);
			}
		} finally {
//			httpClient.close();
		}
	}
	
	/**
	 * get 请求
	 * 
	 * @param url
	 * @param headers
	 * @param proxy
	 * @return
	 * @throws IOException
	 */
	public static Response getNotRedirect(String url, Map<String, String> headers, Map<String, String> params, HttpHost proxy)
			throws IOException {
		HttpClientBuilder builder = HttpClients.custom().setDefaultCookieStore(new BasicCookieStore());
		try {
			URIBuilder uriBuilder = new URIBuilder(url);
			if (params != null) {
				for (String key : params.keySet()) {
					uriBuilder.addParameter(key, params.get(key));
				}
			}
			HttpGet httpGet = new HttpGet(uriBuilder.build());
			if (headers != null) {
				for (String key : headers.keySet()) {
					httpGet.setHeader(key, headers.get(key));
				}
			}

			CloseableHttpResponse response = null;
			Builder builder2 = RequestConfig.custom().setRedirectsEnabled(false).setSocketTimeout(timeout) // 读取数据超时时间
					.setConnectTimeout(timeout) // 连接超时时间
					.setConnectionRequestTimeout(timeout);
			httpGet.setConfig(builder2.build());
			if (proxy != null && "socks".equals(proxy.getSchemeName())) {
				response = setSocksProxy(httpGet, builder, proxy.getHostName(), proxy.getPort(), null, null);
			} else if (proxy != null) {
				response = setHttpProxy(httpGet, builder, proxy.getHostName(), proxy.getPort(),  null, null);
			} else {
				response = builder.build().execute(httpGet);
			}
			HttpEntity responseEntity = response.getEntity();
			String responseBody = null;
			if (responseEntity != null) {				
				responseBody = EntityUtils.toString(responseEntity, "UTF-8");
			}
			Response res = new Response(response.getStatusLine().getStatusCode(), responseBody, response.getAllHeaders(), 0);
			// 去发请求的
//			res.setPreHeaders(httpGet.getAllHeaders());
			return res;
		} catch (Exception e) {
			throw new IOException(e);
		} finally {
		}
	}
	
}
